FreeRADIUS + Google Authenticator + Microsoft ADを使ったClientVPNのMFA構成
ClientVPNでは、ユーザーに対して多要素認証(MFA)を利用することができます。
今回は、MFAを使うために必要なRADIUSサーバを、FreeRADIUSで構築してみたいと思います。
構築手順としては、下記の情報を元にしています。こちらは古いAmazon Linuxを使っているため、今回はAmazon Linux2で作成しています。
また、下記では「WorkSpaces Connect」(現在のAD Connector)を使っていますが、今回はMicrosoft ADを使います。
AWS Solutions Architect ブログ: Google Authenticator を使って Amazon WorkSpaces に多要素認証ログイン
検証する構成
AWSのDirectory Serviceでは、「Microsoft AD」と「AD Connector」がMFAをサポートしています。
そのうち、今回検証するのは「Microsoft AD」を使うパターンです。Active Directoryはオンプレに持たず、AWS上で完結する構成です。
実際には、下記のように検証に必要なリソースだけ作成します。
注意点
本記事で作成した構成の場合、ドメインに所属する全てのユーザーに対して、ClientVPN接続時にMFAが有効となります。
そのため、状況次第では他の構成やSaaSの利用を検討する必要があります。例えば「グループ単位でMFAの有効/無効を分けたい」、「特定ユーザーはスマホを持ってないのでSMSによるOTP認証を使いたい」といった要件の場合です。
全てのケースに対応できるか条件次第ですが、OneLoginやDuo SecurityといったIDaaSで実現可能な場合がありますので、選択肢として持っておくとよいかと思います。
- OneLogin
- Duo Security
FreeRADIUSの構築
それでは構築していきましょう。基本的には冒頭のブログの通りに進めていきます。
まずは「Amazon Linux2」でインスタンスを作成しておきましょう。このインスタンスはプライベートサブネットに配置するので、踏み台などを経由して作業するようにします。
必要なパッケージインストール
サーバにログインして、必要なパッケージをインストールします。
sudo yum -y update sudo yum -y install freeradius freeradius-utils git gcc pam-devel \ qrencode qrencode-libs qrencode-devel
Google Authenticatorのインストール
Google Authenticatorは、epelリポジトリからインストールします。
sudo amazon-linux-extras install -y epel sudo yum -y install google-authenticator
OS設定
RADIUS 経由の認証を許可するグループを作成します。
sudo groupadd radius-enabled
次にホスト名を設定します。
スマホのMFAアプリでは「ユーザー名@ホスト名」という形で表示されるので分かりやすい名前を付けます。外部から名前解決できる必要はありません。(スマホアプリ側で任意に設定できるので必須ではありません。必要に応じて設定してください)
sudo hostnamectl set-hostname (ホスト名) 例 sudo hostnamectl set-hostname myradius.mfa.example
/etc/hosts
にも追記します。
(RADIUSインスタンスのプライベートIP) (ホスト名) 例 10.60.5.195 myradius.mfa.example
FreeRADIUSの設定
rootユーザで起動するように/etc/raddb/radiusd.conf
を修正します。
user = radiusd group = radiusd ↓ user = root group = root
PAM を使うように/etc/raddb/users
を変更します。下記をファイルの最後に追記しましょう。
DEFAULT Group != "radius-enabled", Auth-Type := Reject Reply-Message = "Your account has been disabled." DEFAULT Auth-Type := PAM
/etc/raddb/sites-available/default
を修正します。513行目にある下記をコメントアウトします。
# pam ↓ pam
Google Authenticator のPAM モジュールを使うように/etc/pam.d/radiusd
を修正します。
#%PAM-1.0 auth include password-auth account required pam_nologin.so account include password-auth password include password-auth session include password-auth ↓ #%PAM-1.0 #auth include password-auth #account required pam_nologin.so #account include password-auth #password include password-auth #session include password-auth auth requisite pam_google_authenticator.so account required pam_permit.so session required pam_permit.so
/etc/raddb/clients.conf
を編集してRADIUSクライアントの設定を行います。下記の内容をファイルの最後に追記します。
client 10.60.0.0/16
で指定のCIDRは実際に利用しているVPCのものを指定してください。secret
は任意のパスワードを指定してください。*
や,
、&
などの記号をシークレットに含める場合はシングルクォーテーション'
またはダブルクォーテーション"
で括ってください。- 例:
secret = "L*pzK,G68s&67*he"
- 参考URL:Freeradius as a proxy to Windows IAS - reserved characters in shared secret?
- 例:
client 10.60.0.0/16 { secret = xxxxxxxxxxxxxxxx shortname = from-vpc }
FreeRADIUSの起動
準備ができたので起動したいと思います。まずは自動起動するようにします。
sudo systemctl enable radiusd.service
確認します。
systemctl is-enabled radiusd.service
enabled
と表示されればOKです。ではプロセスを起動します。
sudo systemctl start radiusd.service
これで起動するかと思いましたが、下記のようなエラーが出て失敗しました。
Job for radiusd.service failed because the control process exited with error code. See "systemctl status radiusd.service" and "journalctl -xe" for details.
メッセージに従い、ログを確認しても有用なログはありませんでした。
Failed to start FreeRADIUS high performance RADIUS server..
仕方ないので、デバッグモードで詳細を確認してみます。
sudo radiusd -X
下記のようなメッセージが赤文字で出力されました。pamモジュールが見つからないエラーのようです。
/etc/raddb/sites-enabled/default[514]: Failed to find "pam" as a module or policy. /etc/raddb/sites-enabled/default[514]: Please verify that the configuration exists in /etc/raddb/mods-enabled/pam. /etc/raddb/sites-enabled/default[476]: Errors parsing authenticate section.
pamモジュールを有効にするためにシンボリックリンクを張ります。
sudo ln -s /etc/raddb/mods-available/pam /etc/raddb/mods-enabled/pam
それでは改めて起動してみます。
sudo systemctl start radiusd.service
確認します。
sudo systemctl status radiusd.service
正常に起動できていることが確認できます。
● radiusd.service - FreeRADIUS high performance RADIUS server. Loaded: loaded (/usr/lib/systemd/system/radiusd.service; enabled; vendor preset: disabled) Active: active (running) since 木 2020-04-16 12:32:05 UTC; 43s ago Process: 1790 ExecStart=/usr/sbin/radiusd -d /etc/raddb (code=exited, status=0/SUCCESS) Process: 1787 ExecStartPre=/usr/sbin/radiusd -C (code=exited, status=0/SUCCESS) Process: 1785 ExecStartPre=/bin/chown -R radiusd.radiusd /var/run/radiusd (code=exited, status=0/SUCCESS) Main PID: 1794 (radiusd) CGroup: /system.slice/radiusd.service └─1794 /usr/sbin/radiusd -d /etc/raddb 4月 16 12:32:05 myradius.mfa.example systemd[1]: Starting FreeRADIUS high performance RADIUS server.... 4月 16 12:32:05 myradius.mfa.example systemd[1]: Started FreeRADIUS high performance RADIUS server..
ユーザ登録
実際に利用する際は、Active Directoryと同じ名前のユーザをRADIUSサーバ側にも登録する必要があります。
最初に作成したグループに所属するユーザーを登録しましょう。
今回はcmtest001
というユーザーを登録してみます。
sudo useradd -g radius-enabled cmtest001
ユーザーが登録できたら、このユーザーでgoogle-authenticator
を実行してMFAに対応させます。
sudo -u cmtest001 google-authenticator
コマンドを実行すると、質問と一緒に大きなQRコードが表示されますが、ここでは気にせず質問に全て答えてしまいましょう。
質問には全て「y」で問題ありませんが、その内容を見ておきましょう。
Do you want authentication tokens to be time-based (y/n) y
最初は「時間ベースのトークンにするか」という質問です。
Do you want me to update your "/home/cmtest001/.google_authenticator" file? (y/n)
次は、「作成したユーザーのホームディレクトリにある.google_authenticator
ファイルを更新しますか?」という質問です。
このファイルには、先程のQRコード/キーに関する情報が記載されているので、更新しなければ認証に通りません。
ちなみに、.google_authenticator
はこんな内容です。(数字、文字列はサンプルです)
TOISETWER75ON19GEGEFT2RGLJ " RATE_LIMIT 3 30 " WINDOW_SIZE 17 " DISALLOW_REUSE " TOTP_AUTH 85610581 87856911 87618591 14501245 19286016
次の質問です。
Do you want to disallow multiple uses of the same authentication token? This restricts you to one login about every 30s, but it increases your chances to notice or even prevent man-in-the-middle attacks (y/n)
「同じ認証トークンを複数回使うのを禁止しますか?」という質問です。特に問題ないかと思います。
By default, a new token is generated every 30 seconds by the mobile app. In order to compensate for possible time-skew between the client and the server, we allow an extra token before and after the current time. This allows for a time skew of up to 30 seconds between authentication server and client. If you experience problems with poor time synchronization, you can increase the window from its default size of 3 permitted codes (one previous code, the current code, the next code) to 17 permitted codes (the 8 previous codes, the current code, and the 8 next codes). This will permit for a time skew of up to 4 minutes between client and server. Do you want to do so? (y/n)
デフォルトでは、モバイルアプリによって新しいトークンが30秒ごとに生成されます。 クライアントとサーバー間の可能な時間のずれを補正するために、 現在の時刻の前後に追加のトークンを許可します。 これにより、認証サーバーとクライアントの間で最大30秒のタイムスキューが可能になります。 不十分な時間同期で問題が発生した場合は、ウィンドウのデフォルトサイズを3つの許可されたコード(1つ前のコード、現在のコード、次のコード)から17件の許可されたコード(8つ前のコード、現在のコード、および 次の8つのコード)。 これにより、クライアントとサーバー間で最大4分のタイムスキューが可能になります。 そうしますか?
(ちょっと自信がなかったので「Google翻訳」を使いました)
If the computer that you are logging into isn't hardened against brute-force login attempts, you can enable rate-limiting for the authentication module. By default, this limits attackers to no more than 3 login attempts every 30s. Do you want to enable rate-limiting? (y/n)
「サーバがブルートフォースに対策してなければ、認証モジュールでレートリミットをかけることができます。デフォルトで30秒に3回の制限です。レートリミットしますか?」という質問です。
MFAアプリに登録
質問に全て答えたら、スルーしていたQRコードの対応を行います。これを手元のMFAアプリでスキャンしましょう。
私は「Authy」というアプリを使っているので、そちらでスキャンしました。
同時に出力されるURLにアクセスしても同じQRコードが表示されます。(赤枠の部分)
利用者に先程のURLを共有してスキャンしてもらうか、スキャンが難しい場合は下記のキーを手動で入力することでMFAアプリに登録することもできます。
Authyの場合だと画面下にある「Enter key manually」をクリックすると
こんな感じでキーを手動で登録できます。
いずれかの方法でMFAアプリに入力できたら、このように「ユーザー名@ホスト名」で登録されました。
表示名やロゴは後から変更できます。
認証テスト
ここまでできたら、単体で認証のテストを行います。コマンドの書式は以下です。
radtest [ユーザ名] [MFAコード] [RADIUSサーバのプライベートIP]:1812 10 [クライアントの共有シークレット]
MFAコードにはスマホのアプリに表示される6桁の数字を入れます。共有シークレットに記号を入れていてシェルからの入力に失敗する時は'
や"
で括って指定します。下記は例です。
radtest cmtest001 948712 10.60.5.195:1812 10 'L*pzK,G68s&67*he'
問題なければ下記のようにReceived Access-Accept
と出力されます。
Sent Access-Request Id 209 from 0.0.0.0:49270 to 10.60.5.195:1812 length 79 User-Name = "cmtest001" User-Password = "596580" NAS-IP-Address = 10.60.5.195 NAS-Port = 10 Message-Authenticator = 0x00 Cleartext-Password = "596580" Received Access-Accept Id 209 from 10.60.5.195:1812 to 0.0.0.0:0 length 20
Microsoft ADの設定
次にAWS側の設定を行います。ディレクトリサービスとしてMicrosoft ADを使います。
Microsoft ADの作成
オンプレADではなくMicrosoft ADを使う場合は、ここでディレクトリを作成します。 ディレクトリタイプに「Microsoft AD」を選択して作成します。
ディレクトリ情報を記入していきます。
項目 | 内容 |
---|---|
ディレクトリのタイプ | 利用する規模感に応じて選択。今回は検証なので「Standard」を選択。 |
ディレクトリのDNS名 | ディレクトリのActive Directoryで使用するドメイン名。FreeRADIUSの設定で指定したドメインと違っていて問題なし。適当なものを指定。 |
ディレクトリのNetBIOS名 | 任意 |
ディレクトリの説明 | 任意 |
Adminパスワード | Microsoft ADで利用できる管理者アカウントのパスワード。(Administratorは利用不可) |
ディレクトリを作成するVPCとサブネットを指定します。インターネットに露出しないプライベートなサブネットに作成しましょう。
(FreeRADIUSのサーバと同じサブネットである必要はありません)
問題なければ作成します。
Security Groupに注意
Microsoft ADは、それ自体がディレクトリサービスを提供するものなので、デフォルトではアウトバウンドのセキュリティグループがAD Connectorのものとは異なります。
Microsoft ADでMFAを利用する場合は、RADIUSサーバへの認証の通信が発生するので、このトラフィックを明示的に許可する必要があります。
また、RADIUSサーバ側でも、Microsoft ADからの「UDP 1812ポート」へのアクセスを許可します。
そのため、Microsoft ADのセキュリティグループにアウトバウンドの許可設定を追加しましょう。
まず、Directory Serviceのコンソールから「ディレクトリID」を確認します。
次に、VPCまたはEC2のコンソールからセキュリティグループの画面を開いて、確認したディレクトリIDで検索します。(d-xxxxxxx_controllers
というグループ名になっています)
見つかったセキュリティグループに下記のように許可ルールを追加します。
項目 | 設定内容 |
---|---|
タイプ | カスタムUDPルール |
プロトコル | UDP |
ポート範囲 | 1812 |
送信先 | RADIUSサーバのセキュリティグループID |
RADIUSサーバ側のセキュリティグループにも、許可ルールを追加します。
項目 | 設定内容 |
---|---|
タイプ | カスタムUDPルール |
プロトコル | UDP |
ポート範囲 | 1812 |
ソース | Microsoft ADのセキュリティグループID |
MFAの有効化
作成したMicrosoft ADでMFA設定を有効化します。該当ディレクトリのコンソールで「ネットワークとセキュリティ」タブを表示します。
画面の一番下にMFAの設定箇所があるので、プルダウンから「有効化」をクリックします。
下記の通り設定します。
項目 | 設定内容 |
---|---|
表示ラベル | 分かりやすいものを指定 |
RADIUSサーバのDNS名またはIPアドレス | FreeRADIUSサーバのプライベートIP。複数指定する場合はカンマ区切りで指定。 |
ポート | 1812 |
共有シークレットコード | /etc/raddb/clients.conf で指定したsecret の文字列 |
確認済みの共有シークレットコード | 上記と同じもの |
プロトコル | PAP |
サーバタイムアウト | 適当な秒数を指定 |
RADIUSリクエストの最大再試行数 | 適当な回数を指定 |
しばらくしてステータスが「完了」になればOKです。
ClientVPNの設定
次にClientVPNの設定を行います。
「認証情報」のセクションで「ユーザーベースの認証を使用」にチェックを入れて、先程作成したMicrosoft ADのディレクトリIDを指定します。(相互認証と併用することも可能です)
後は、特別な設定はありません。関連付けるサブネットを設定します。
今回は検証なので、VPC全体に対して全てのアクセスを許可する認証ルールを入れます。
この辺りはご自身の環境、要件に合わせて設定してください。
ClientVPNのエンドポイントの作成が完了したら、コンフィグファイルをダウンロードして、利用するVPNクライアントに設定を追加しておきましょう。
Microsoft AD環境での動作テスト
Microsoft ADに適当なユーザーを追加します。
本来は、ドメインに参加したEC2やリモートから「RSAT」などで接続してユーザ作成しますが、今回は横着をしてWorkSpacesのコンソールからユーザー作成だけ行います。
AWS Managed Microsoft AD のユーザーとグループを管理する - AWS Directory Service
マネジメントコンソールからユーザーを作成するために、WorkSpacesのコンソールにアクセスします。
コンソール上で「WorkSpacesの起動」をクリックします(実際にはWorkSpacesは作成しません)
次に先程作成したMicrosoft ADを選択肢ます。サブネットは適当で構いません。
(実際にWorkSpacesを展開するサブネットの指定になりますが、今回は作成せず途中でキャンセルするので適当でOKです)
作成したいユーザ情報を入力します。
RADIUSサーバに登録したのと同じユーザ「cmtest001」を登録します。
登録できたら、「すべてのユーザーの表示」をクリックして、cmtest001ユーザが作成できていることを確認します。
ユーザーの作成が確認できたら、「キャンセル」をクリックしてウィザードを途中で終了させます。
次に、Directory Serviceのコンソールに戻ります。
先程作成したユーザー(cmtest001)にはパスワードがまだ設定されていません。そのため、ここで「cmtest001」のパスワードを設定します。
作成済みのMicrosoft ADの画面を開いて、「ユーザーパスワードのリセット」をクリックします。
下記のようなウィンドウが開くので、パスワードをリセットしたいユーザー名、設定するパスワードを入力して「パスワードのリセット」をクリックします。
これでパスワードの設定が完了しました。
VPNクライアントから接続テスト
クライアントは、MacOSから「Tunnelblick 3.8.2 (build 5480)」で接続します。
(VPNのコンフィグファイルは既にインポート済みとします)
ユーザ名「cmtest001」とパスワードリセットで設定したパスワードを入力します。
次にMFAコードの入力を促されるので、スマホのMFAアプリで表示される6桁のコードを入力します。
(もしMFAの入力画面が現れなかったらTunnelblickをアップデートしてみてください)
スマホのMFAコードの表示です。
接続完了後に下記のような警告が出たら「了解」をクリックして閉じてください。
VPN接続後、FreeRADIUSのサーバに直接プライベートIPで接続してみると、下記の通り無事にSSHできました。
(ClientVPN経由でリソースにアクセスできるように、内容に応じて「接続される」側のセキュリティグループに許可ルールを追加しておきましょう)
検証後の環境削除について
検証が完了して作った環境を削除するときは、下記の点に気をつけてください。
- 関連アプリケーションの無効化
- ClientVPNの削除
関連アプリケーションの無効化
今回は横着してWorkSpaces側からADユーザを作成したので、ディレクトリサービス側でWorkSpacesが有効になっています。
コレを無効にするには、WorkSpacesの画面で対象ディレクトリに対して「登録解除」を行います。
ステータスが無効になりました。
ClientVPNエンドポイントの削除
次に、このディレクトリを認証に利用しているClientVPNのエンドポイントを削除します。
上記のアプリ一覧「AWSアプリおよびサービス」には、ClientVPNが記載されていません。そのため、下記のようなエラーが出てもClientVPNの存在が原因だと気付きづらいので注意しましょう。
FreeRADIUSの冗長化
実運用を考えると、Multi-AZを前提としてFreeRADIUSサーバ自体を冗長化したいというニーズもあると思います。
この場合は、同じ設定のインスタンスをAMIやスナップショットからコピーして冗長構成にします。そして、Microsoft ADのMFA設定の中で「RADIUSサーバのIPをカンマ(,)で複数登録」すればよいかと思います。
また、/home/[User]
以下のディレクトリをrsyncなどで定期的に同期します。一方向で同期させると構成の維持など運用が面倒な場合は、/home
以下はEFSで共有させてもいいかもしれません。
(Multi-AZで展開するEFSの料金が別途発生するので、確認の上で採用ください)
最後に
Microsoft ADで行う時は、セキュリティグループのアウトバウンドにルールを追加しなくてはいけない点に気づかず、検証当初にかなり悩みました。
他にも細かいところで何度かつまづきましたが、気がついた点はこのブログに詰め込みました。この記事がどなたかのお役に立てれば幸いです。
以上です。